<template>
  <el-form label-width="150px" :model="spuInfo" :rules="rules" ref="formRef">
    <el-form-item label="SPU名称" prop="spuName">
      <el-input
        type="text"
        placeholder="SPU名称"
        v-model="spuInfo.spuName"
      ></el-input>
    </el-form-item>
    <el-form-item label="品牌" prop="tmId">
      <el-select v-model="spuInfo.tmId">
        <el-option
          :label="tm.tmName"
          :value="(tm.id as number)"
          v-for="tm in trademarkList"
          :key="tm.id"
        ></el-option>
      </el-select>
    </el-form-item>
    <el-form-item label="SPU描述" prop="description">
      <el-input
        type="textarea"
        placeholder="SPU描述"
        v-model="spuInfo.description"
      ></el-input>
    </el-form-item>

    <el-form-item label="SPU图片" prop="spuImageList">
      <!-- multiple: 多选 -->
      <el-upload
        multiple
        v-model:file-list="(spuInfo.spuImageList as any)"
        list-type="picture-card"
        :action="`${BASE_UPLOAD}/admin/product/fileUpload`"
        :on-preview="handlePictureCardPreview"
        :on-remove="handleRemove"
        :on-success="handleSuccess"
      >
        <el-icon><Plus /></el-icon>
      </el-upload>

      <el-dialog v-model="dialogVisible">
        <img w-full :src="dialogImageUrl" alt="Preview Image" />
      </el-dialog>
    </el-form-item>

    <el-form-item label="SPU销售属性" prop="spuSaleAttrList">
      <div>
        <el-select :placeholder="selectText" v-model="valueIdValueName">
          <el-option
            :label="attr.name"
            :value="attr.id + ':' + attr.name"
            v-for="attr in restSaleAttrList"
            :key="attr.id"
          ></el-option>
        </el-select>
        <el-button
          type="primary"
          :icon="Plus"
          :disabled="!valueIdValueName"
          @click="addSpuSaleAttr"
          >添加属性值</el-button
        >
      </div>

      <el-table :data="spuInfo.spuSaleAttrList" style="margin-top: 10px">
        <el-table-column
          label="序号"
          type="index"
          width="80px"
          align="center"
        ></el-table-column>
        <el-table-column label="属性名" prop="saleAttrName"></el-table-column>
        <el-table-column label="属性值名称列表">
          <template v-slot="{ row }">
            <el-tag
              closable
              v-for="(value, index) in row.spuSaleAttrValueList"
              :key="value.id"
              @close="row.spuSaleAttrValueList.splice(index, 1)"
              >{{ value.saleAttrValueName }}</el-tag
            >
            <el-input
              v-if="row.isEdit"
              style="width: 100px"
              @blur="toShow(row)"
              ref="inputRef"
              v-model="valueName"
              placeholder="名称"
            ></el-input>
            <el-button
              v-else
              size="small"
              :icon="Plus"
              @click="toEdit(row)"
            ></el-button>
          </template>
        </el-table-column>
        <el-table-column label="操作">
          <template v-slot="{ $index }">
            <el-button
              type="danger"
              :icon="Delete"
              @click="spuInfo.spuSaleAttrList.splice($index, 1)"
            ></el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-form-item>

    <el-form-item>
      <el-button type="primary" @click="save" :loading="saveLoading"
        >保存</el-button
      >
      <el-button @click="$emit('setShowStatus', ShowStatus.SPU_LIST)"
        >取消</el-button
      >
    </el-form-item>
  </el-form>
</template>

<script lang="ts">
export default {
  name: 'SpuForm',
  components: { Plus },
};
</script>

<script lang="ts" setup>
import { getAllTrademarkListApi } from '@/api/product/trademark';
import type {
  BaseSaleAttrListModel,
  SpuModel,
  SpuSaleAttrModel,
} from '@/api/product/model/spuModel';
import type { TrademarksModel } from '@/api/product/model/trademarkModel';
import { Delete, Plus } from '@element-plus/icons-vue';
import type {
  InputInstance,
  UploadProps,
  FormInstance,
  FormRules,
} from 'element-plus';
import { ElMessage } from 'element-plus';
import { ref, reactive, onMounted, computed, nextTick } from 'vue';
import { ShowStatus } from '../types';
import {
  addOrUpdateSpuApi,
  getBaseSaleAttrListApi,
  getSpuImageListApi,
  getSpuSaleAttrListApi,
} from '@/api/product/spu';
import { cloneDeep } from 'lodash';

// 声明接收props
const props = defineProps<{
  spu: SpuModel;
}>();

// 声明一个用于收集spu表单数据的spu详情信息对象
const spuInfo = reactive<SpuModel>(props.spu);

// 声明定义自定义事件, 返回的是分发事件的函数
const emit = defineEmits<{
  (e: 'setShowStatus', value: ShowStatus): void;
}>();

const saveLoading = ref(false);
/* 
请求添加或修改spu
*/
const save = async () => {
  // 先校验
  // formRef.value?.validate((valid) => {
  //   if (valid) {
  //     alert('准备请求...')
  //   }
  // })
  // 校验的返回值是一个promise, 校验成功promise就会成功

  // 在发请求对spuInfo进行数据整理
  // 对spuInfo产生一个拷贝对象
  const cloneSpuInfo = cloneDeep(spuInfo);

  // 需要在数据类型添加：response的结构
  // 给name的值添加为imgName属性
  // 将imgUrl或response.data的值给imgUrl
  cloneSpuInfo.spuImageList = cloneSpuInfo.spuImageList.map((item) => ({
    imgName: item.name!,
    imgUrl: item.response ? item.response.data : item.imgUrl,
  }));

  /* 
  处理 spuSaleAttr对象
  删除isEdit属性
  过滤掉没有属性值名称的属性对象
*/
  cloneSpuInfo.spuSaleAttrList = cloneSpuInfo.spuSaleAttrList.filter((item) => {
    //如果有属性值，就要留下来
    if (item.spuSaleAttrValueList.length > 0) {
      // 删除isEdit属性
      delete item.isEdit;
      return true;
    }
    return false;
  });

  // 显示loading
  saveLoading.value = true;

  try {
    // 发送添加/更新的请求: addOrUpdateSpuApi
    await addOrUpdateSpuApi(cloneSpuInfo);
    // 请求成功后: 提示 / 显示列表页面
    ElMessage.success('保存成功!');
    emit('setShowStatus', ShowStatus.SPU_LIST);
    // 隐藏loading
    // saveLoading.value = false
  } catch (error) {
    // 隐藏loading
    // saveLoading.value = false
  } finally {
    // 请求成功或失败都要隐藏loading
    saveLoading.value = false;
  }
};

/* **表单校验 start** */
const formRef = ref<FormInstance>();
const rules: FormRules = {
  spuName: [{ required: true, message: 'spu名称是必须的', trigger: 'blur' }],
  tmId: [{ required: true, message: '品牌是必须的' }],
  description: [{ required: true, message: '描述是必须的' }],
  spuImageList: [{ required: true, message: '必须上传spu图片', type: 'array' }],
  spuSaleAttrList: [
    { required: true, message: '必须指定spu销售属性', type: 'array' },
  ],
};
/* **表单校验 end** */

/* **spu销售属性处理 start** */
const inputRef = ref<InputInstance>();
const valueName = ref(''); // 保存输入的属性值名称
// 切换为查看模式
const toShow = (row: SpuSaleAttrModel) => {
  // 必须输入了名称
  if (valueName.value) {
    // 判断是否不重复
    const notRepeat = row.spuSaleAttrValueList.every(
      (item) => item.saleAttrValueName !== valueName.value
    );
    if (notRepeat) {
      // 不能重复
      // 创建一个属性值对象
      const attrValu = {
        saleAttrValueName: valueName.value,
        baseSaleAttrId: row.baseSaleAttrId,
      };
      // 添加到属性值列表中
      row.spuSaleAttrValueList.push(attrValu);
    }
  }
  // 变为查看模式
  row.isEdit = false;
  // 清除收集的输入数据
  valueName.value = '';
};
// 切换为编辑模式
const toEdit = (row: SpuSaleAttrModel) => {
  // isEdit变为true,
  row.isEdit = true;
  // 自动获得焦点
  nextTick(() => {
    inputRef.value?.focus();
  });
};
/* **spu销售属性处理 end** */

/* 初始化请求 start */
// 所有品牌的列表
const trademarkList = ref<TrademarksModel>([]);
// 所有销售属性的列表
const saleAttrList = ref<BaseSaleAttrListModel>([]);

// 收集选择销售属性的id和name   id:name
const valueIdValueName = ref('');

// 点击添加一个新的spu销售属性
const addSpuSaleAttr = () => {
  // 对valueIdValueName进行拆分, 得到 id和name
  const [id, name] = valueIdValueName.value.split(':');
  // 创建一个新的spu销售属性对象, 并添加到对应的列表中
  spuInfo.spuSaleAttrList.push({
    baseSaleAttrId: +id,
    saleAttrName: name,
    spuSaleAttrValueList: [],
  });
  // 清除选择收集的valueIdValueName
  valueIdValueName.value = '';
};

// 剩余可选的销售属性列表
const restSaleAttrList = computed(() => {
  return saleAttrList.value.filter((attr) => {
    // attr.name在spuInfo.spuSaleAttrList中有没有对应的
    return !spuInfo.spuSaleAttrList.some(
      (saleAttr) => saleAttr.saleAttrName === attr.name
    );
  });
});
// 计算出下拉列表的提示文本
const selectText = computed(() => {
  const length = restSaleAttrList.value.length;
  return length === 0 ? '没有啦!' : `还有${length}个可选的`;
});

/* 
1. 获取所有品牌列表 trademark.getAllTrademarkListApi()  trademarkList
2. 获取基础销售属性列表  spu.getBaseSaleAttrListApi()  saleAttrList
3. 获取spu图片列表   spu.getSpuImageListApi(spuId)  spuInfo.spuImageList
4. 获取spu销售属性列表  spu.getSpuSaleAttrListApi(spuId)  spuInfo.spuSaleAttrList
*/
onMounted(async () => {
  trademarkList.value = await getAllTrademarkListApi();
});
onMounted(async () => {
  saleAttrList.value = await getBaseSaleAttrListApi();
});
onMounted(async () => {
  // 如果没有spuId, 不发请求
  if (!spuInfo.id) return;

  const spuImageList = await getSpuImageListApi(spuInfo.id!); // 此时!可以不写, 因为前面有判断

  // 使用forEach
  // spuImageList.forEach(item => {
  //   item.name = item.imgName
  //   item.url = item.imgUrl
  // })

  /* 
  通用问题: 请求得到的数据结构不能满足显示的需求
	Upload组件需要的图片对象{name, url}
	而我们的数据在{imgName, imgUrl}
  解决: 当请求得到数据后, 对数据进行整理
      将imgName值给name属性, 将imgUrl的值给url属性
  */
  spuInfo.spuImageList = spuImageList.map((item) => ({
    ...item,
    name: item.imgName,
    url: item.imgUrl,
  }));
});
onMounted(async () => {
  // 如果没有spuId, 不发请求
  if (!spuInfo.id) return;

  const spuSaleAttrList = await getSpuSaleAttrListApi(spuInfo.id as number);
  spuInfo.spuSaleAttrList = spuSaleAttrList;
});

/* 初始化请求 end */

/* 图片上传处理 start */
const BASE_UPLOAD = import.meta.env.VITE_BASE_URL; // 代理的基础路径
// 大图url
const dialogImageUrl = ref('');
// 是否显示大图
const dialogVisible = ref(false);

// 点击删除回调
// uploadFile: 要删除的图片对象
// uploadFiles: 剩余的图片列表
const handleRemove: UploadProps['onRemove'] = (uploadFile, uploadFiles) => {
  console.log(uploadFile, uploadFiles);
  spuInfo.spuImageList = uploadFiles as any; // 数据等到发请求前进行整理
};

// 点击放大镜的回调
// uploadFile: 点击的图片对象
const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile) => {
  // 指定要显示的大图url
  dialogImageUrl.value = uploadFile.url!;
  // 显示dialog
  dialogVisible.value = true;
};
// 上传成功的回调
// response: 上传请求的响应体数据  {data: 图片的url}
// uploadFile: 上传成功的图片对象
// uploadFiles: 已上传的图片列表
const handleSuccess: UploadProps['onSuccess'] = (
  response,
  uploadFile,
  uploadFiles
) => {
  console.log('onSuccess', uploadFiles);
  spuInfo.spuImageList = uploadFiles as any; // 数据等到发请求前进行整理

  // 在上传图片成功后, 手动清除错误信息
  formRef.value?.clearValidate(['spuImageList']);
};
/* 图片上传处理 end */
</script>

<style lang="scss" scoped></style>
